package edu.bit.basic.list;


import java.util.*;

public class MyArrayList<E> extends AbstractList<E> implements List<E> {
    private int size;
    private int modCount;
    private static final int DEFAULT_CAPACITY = 10;
    private Object[] elementData;

    public MyArrayList(int size) {
        if(size < 0) {
            throw new OutOfMemoryError();
        }
        this.elementData = new Object[size];
    }

    public MyArrayList() {
        this(DEFAULT_CAPACITY);
    }


    @Override
    public int size() {
        return this.size;
    }

    @Override
    public boolean add(E E) {
        this.add(this.size, E);
        return true;
    }

    void rangeCheckForAdd(int index) {
        if(index < 0 || index > this.size) {
            throw new IndexOutOfBoundsException();
        }
    }

    void rangeCheckForGet(int index) {
        if(index < 0 || index > this.size) {
            throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public void add(int i, E e) {
        //rangeCheckForAdd(i);
        ensureCapacity(this.size+1);
        this.elementData[this.size++] = e;
    }

    void ensureCapacity(int capcity) {
        this.modCount++;
        if(capcity > elementData.length) {
            int alloc = this.elementData.length << 1 ;
            if(alloc < capcity) {
                alloc = capcity;
            }
            grow(alloc);
        }

    }

    void grow(int capacity) {
        this.elementData = Arrays.copyOf(this.elementData, capacity);
    }


    private void fastRemove(int index) {
        ++this.modCount;
        int count = this.size - index - 1;
        if(count > 0) {
            System.arraycopy(this.elementData, index+1, this.elementData, index, count);
        }
        this.elementData[--this.size] = null;
    }

    @Override
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < this.size; index++) {
                if (null == elementData[index]) {
                    fastRemove(index);
                    return true;
                }
            }
        } else {
            for (int index = 0; index < this.size; index++) {
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public E remove(int i) {
        rangeCheckForGet(i);
        Object e = elementData[i];
        fastRemove(i);
        return (E)e;
    }


    @Override
    public E get(int i) {
        rangeCheckForGet(i);
        Object e = elementData[i];
        return (E)e;
    }


    private class Itr implements Iterator<E> {
        private int curIndex;
        int lastIndex;
        int expectedModCount;


        @Override
        public boolean hasNext() {
            return this.curIndex != MyArrayList.this.size;
        }

        @Override
        public E next() {
            if(!hasNext()) {
                throw new NoSuchElementException();
            } else {
                Object[] data = MyArrayList.this.elementData;
                if(this.curIndex >= data.length) {
                    throw new ConcurrentModificationException();
                } else {
                    this.lastIndex = this.curIndex++;
                    return (E)data[this.lastIndex];
                }
            }
        }

        final void checkForCoModify() {
            if (MyArrayList.this.modCount != this.expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }
    }
}
